#include "ProtoFieldDescriptor.h"
#include "ProtoUtil.h"
#include "MessageFactory.h"
#include "Message.h"

#define WIRE_TAG_TYPE_BITS	3

namespace miniproto
{

ProtoFieldDescriptor::ProtoFieldDescriptor()
{
	this->message_ = NULL;
}

ProtoFieldDescriptor::~ProtoFieldDescriptor()
{

}

void ProtoFieldDescriptor::set(const uint8_t field_type, const ::std::string &field_name, const uint32_t number)
{
	this->field_type_ = field_type;
	this->field_name_ = field_name;
	this->number_ = number;
	this->message_ = NULL;
}

void ProtoFieldDescriptor::set_message(const uint8_t field_type, const ::std::string &field_name, const uint32_t number, ::miniproto::Message *message)
{
	this->field_type_ = field_type;
	this->field_name_ = field_name;
	this->number_ = number;
	if (this->base_field_type() == ProtoFieldDescriptor::MESSAGE)
	{
		this->message_ = message;
	}
}

uint8_t ProtoFieldDescriptor::field_type() const
{
	return this->field_type_;
}

bool ProtoFieldDescriptor::is_array() const
{
	return ::miniproto::is_array_field(this->field_type_);
}

uint8_t ProtoFieldDescriptor::base_field_type() const
{
	return ::miniproto::base_field_type(this->field_type_);
}

const ::std::string &ProtoFieldDescriptor::field_name() const
{
	return this->field_name_;
}

uint32_t ProtoFieldDescriptor::number() const
{
	return this->number_;
}


int32_t ProtoFieldDescriptor::wire_type() const
{
	int base_type = this->base_field_type();
	if (base_type == ProtoFieldDescriptor::STRING || base_type == ProtoFieldDescriptor::BYTES)
		return ProtoFieldDescriptor::WIRE_STRING_OR_MESSAGE;
	if (base_type == ProtoFieldDescriptor::MESSAGE)
		return ProtoFieldDescriptor::WIRE_STRING_OR_MESSAGE;
	if (base_type == ProtoFieldDescriptor::DOUBLE)
		return ProtoFieldDescriptor::WIRE_DOUBLE;
	if (base_type == ProtoFieldDescriptor::FLOAT)
		return ProtoFieldDescriptor::WIRE_FLOAT;
	return ProtoFieldDescriptor::WIRE_VARINT;
}

uint32_t ProtoFieldDescriptor::wire_tag() const
{
	return ::miniproto::wire_tag(this->number_, this->wire_type());
}

void ProtoFieldDescriptor::wire_tag_split(const uint32_t tag, uint32_t *number, int32_t *wire_type)
{
	::miniproto::wire_tag_split(tag, number, wire_type);
}

::miniproto::Message *ProtoFieldDescriptor::NewMessage() const
{
	if (this->message_ != NULL)
		return this->message_->New();
	return NULL;
}

}
